package file

import (
	"os"
	"path"
	"path/filepath"
	"strings"
	"time"

	"system-admin/config"

	"192.168.1.75/go-pkg/errorx"
	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/timewheel"
	"github.com/gin-gonic/gin"
	"github.com/samber/lo"
)

var removeExpiredFileTimeWheel *timewheel.TimeWheel

// 时间轮初始化
func init() {
	// 过期文件的检查及删除
	removeExpiredFileTimeWheel = timewheel.New(time.Second, 60, func(val interface{}) {
		if saveDir, ok := val.(string); ok {
			diffTime := int64(1800)      // 超时时间为半个小时
			nowTime := time.Now().Unix() // 当前时间，使用Unix时间戳
			_ = filepath.Walk(saveDir, func(path string, fi os.FileInfo, err error) error {
				if !fi.IsDir() {
					fileTime := fi.ModTime().Unix()
					if (nowTime - fileTime) > diffTime { // 判断文件是否过期
						os.Remove(path)
					}
				}
				return nil
			})
		}
	})
	removeExpiredFileTimeWheel.Start()
}

// ConfirmFile 文件确认
// 未被确认的文件，将会在半个小时后被删除
func ConfirmFile(file string) (dstURL string, err error) {
	if file == "" {
		return "", errorx.New("文件路径不能为空", -1)
	}
	dstDir := filepath.Dir(filepath.Dir(file))
	dstDir = path.Join(dstDir, time.Now().Format("2006-01"))
	return SaveUploadFileTo(file, dstDir)
}

// UploadFile 上传固件
// 文件上传到./upload/tmp 临时文件夹
// 如果1个小时内没有被确认移动走，则会在下载上传时被删除
// 返回上传信息 struct{name,url},err
func UploadFile(c *gin.Context) (url, fileName string, err error) {
	// 获取保存位置参数
	systemName := c.PostForm("system_name")
	Dir := c.PostForm("dir")
	// 判断系统名称是否有效
	if !lo.Contains([]string{"system-admin", "device-admin", "sale-admin", "mini-app"}, systemName) {
		return "", "", errorx.New("无效的系统名称", -1)
	}
	saveDir := path.Join(config.Config.FileSaveDir, systemName, Dir, "temp")
	// 创建目标文件夹-temp
	// 先判断是否存在，不存在就直接创建
	_, err = os.Stat(saveDir)
	if err != nil {
		err = os.MkdirAll(saveDir, os.ModePerm)
		if err != nil {
			return "", "", errorx.New("创建文件夹失败", -1)
		}
	}
	// 处理上传的文件
	file, err := c.FormFile("file")
	if err != nil {
		return "", "", errorx.New("未获取到上传的文件", -1)
	}
	primaryKey, err := helper.UUID{}.String()
	if err != nil {
		return "", "", errorx.New("新建文件名失败", -1)
	}

	// 延期检查删除过期的文件
	removeExpiredFileTimeWheel.AddTimer(primaryKey, time.Minute*30, saveDir)

	// 保存上传的文件
	var newFilename string
	fileNames := strings.Split(file.Filename, ".")
	if len(fileNames) > 2 {
		fileNames[0] = primaryKey
		newFilename = strings.Join(fileNames, ".")
	} else {
		newFilename = primaryKey + path.Ext(file.Filename)
	}

	err = c.SaveUploadedFile(file, path.Join(saveDir, newFilename))
	if err != nil {
		return "", "", errorx.New("文件保存失败", -1)
	}
	// 返回上传结果
	return path.Join(saveDir, newFilename), strings.Split(file.Filename, ".")[0], nil
}

// SaveUploadFileTo 保存上传的文件到指定位置，防止过期清理
func SaveUploadFileTo(srcFile string, dstDir string) (string, error) {
	// 判断原始文件是否存在
	_, err := os.Stat(srcFile)
	if err != nil {
		return "", errorx.New("源文件不存在", -1)
	}
	// 判断路径否存在，不存在则创建
	_, err = os.Stat(dstDir)
	if err != nil {
		err = os.MkdirAll(dstDir, os.ModePerm)
		if err != nil {
			return "", errorx.New("创建目标文件夹失败", -1)
		}
	}
	// 将文件移动到指定目录
	err = os.Rename(srcFile, path.Join(dstDir, filepath.Base(srcFile)))
	if err != nil {
		return "", errorx.New("文件移动失败", -1)
	}
	return path.Join(dstDir, filepath.Base(srcFile)), nil
}
